Skip to main content

RTC

This chapter explains how to read and write the Luckfox Lume RTC and synchronize the system clock.

1. RTC

An RTC (Real-Time Clock) is a dedicated hardware timekeeping module in embedded systems and microcontrollers. It typically has an independent backup power supply, commonly a coin cell, so it can continue running and keep track of the date and time when the device's main power is disconnected. By retaining the time during power loss, an RTC provides a stable time reference for applications such as log timestamps, scheduled wakeups, system clock synchronization, and scheduled tasks.

2. RTC Testing (Shell)

2.1 Viewing RTC Devices

Run on the board:

ls -l /dev/rtc*
cat /sys/class/rtc/rtc0/name
dmesg | grep -i rtc

2.2 Reading and Writing the RTC

Linux includes the hwclock tool for reading the current date and time from the RTC hardware clock. Run the following command to display the RTC time.

  1. Read the RTC time:

    hwclock --show

    Specify the RTC device:

    hwclock -f /dev/rtc0 --show
  2. Set the RTC time:

    date -s "2026-09-02 12:00:00" # Set the system time first
    hwclock -f /dev/rtc0 --systohc # Write the system time to the RTC
  3. Restore the system time from the RTC:

    hwclock -f /dev/rtc0 --hctosys

3. Reading and Writing the RTC (Python)

  1. Complete code: By default, the program only reads the RTC. write writes the system time to the RTC, and sync restores the system time from the RTC. Both operations read the RTC afterward so you can check the result.

    #!/usr/bin/env python3
    import subprocess
    import sys

    RTC_DEVICE = "/dev/rtc0"


    def run_hwclock(option):
    result = subprocess.run(
    ["hwclock", "-f", RTC_DEVICE, "-u", option],
    capture_output=True, text=True, check=True
    )
    return result.stdout.strip()


    def get_rtc_time():
    rtc_time = run_hwclock("-r")
    if not rtc_time:
    raise RuntimeError("hwclock returned no time")
    print(f"RTC time: {rtc_time}")


    def set_rtc_from_system():
    run_hwclock("-w")
    print("RTC time set from system (UTC).")


    def sync_system_from_rtc():
    run_hwclock("-s")
    print("System time loaded from RTC (UTC).")


    def main():
    if len(sys.argv) > 2:
    print("Usage: RTC.py [read|write|sync]", file=sys.stderr)
    return 1
    mode = sys.argv[1] if len(sys.argv) == 2 else "read"
    if mode not in ("read", "write", "sync"):
    print("Usage: RTC.py [read|write|sync]", file=sys.stderr)
    return 1

    try:
    if mode == "write":
    set_rtc_from_system()
    elif mode == "sync":
    sync_system_from_rtc()
    get_rtc_time()
    except subprocess.CalledProcessError as error:
    message = error.stderr.strip() or f"hwclock exited with {error.returncode}"
    print(f"RTC error: {message}", file=sys.stderr)
    return 1
    except (OSError, RuntimeError) as error:
    print(f"RTC error: {error}", file=sys.stderr)
    return 1
    return 0


    if __name__ == "__main__":
    sys.exit(main())
  2. Read the RTC time:

    rtc_time = run_hwclock("-r")

    Call hwclock -f /dev/rtc0 -u -r to retrieve the time. check=True checks the command's exit status. If the command fails or produces no time output, an error is reported and subsequent operations are not performed.

  3. Write the system time to the RTC:

    run_hwclock("-w")

    Write the current system time to the RTC in UTC. Before running this operation, verify the system time by setting it manually or synchronizing it through NTP.

  4. Restore the system time from the RTC:

    run_hwclock("-s")

    Synchronize the Linux system clock with the RTC time. This requires root privileges.

  5. Main program:

    if mode == "write":
    set_rtc_from_system()
    elif mode == "sync":
    sync_system_from_rtc()
    get_rtc_time()

    read is read-only. write and sync must be explicitly specified to prevent accidental clock changes when running the example. The program returns a nonzero exit code on failure.

  6. Run the program:

    python3 RTC.py read # Read the RTC time
    python3 RTC.py write # Write after verifying the system time
    python3 RTC.py sync # Restore the system time from the RTC when needed
    date

    Output:

4. Reading and Writing the RTC (C)

  1. Complete code:

    #define _POSIX_C_SOURCE 200809L
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/wait.h>

    #define HWCLOCK "hwclock -f /dev/rtc0 -u "

    static int command_succeeded(int status)
    {
    return status != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0;
    }

    static int get_rtc_time(void)
    {
    char rtc_time[256];
    FILE *pipe = popen(HWCLOCK "-r", "r");
    if (!pipe) {
    perror("RTC read");
    return -1;
    }

    int got_time = fgets(rtc_time, sizeof(rtc_time), pipe) != NULL;
    int read_failed = ferror(pipe);
    int status = pclose(pipe);
    if (!got_time || read_failed || !command_succeeded(status)) {
    fprintf(stderr, "RTC error: hwclock read failed\n");
    return -1;
    }

    rtc_time[strcspn(rtc_time, "\r\n")] = '\0';
    if (rtc_time[0] == '\0') {
    fprintf(stderr, "RTC error: hwclock returned no time\n");
    return -1;
    }
    printf("RTC time: %s\n", rtc_time);
    return 0;
    }

    static int set_rtc_from_system(void)
    {
    if (!command_succeeded(system(HWCLOCK "-w"))) {
    fprintf(stderr, "RTC error: cannot write system time to RTC\n");
    return -1;
    }
    puts("RTC time set from system (UTC).");
    fflush(stdout);
    return 0;
    }

    static int sync_system_from_rtc(void)
    {
    if (!command_succeeded(system(HWCLOCK "-s"))) {
    fprintf(stderr, "RTC error: cannot set system time from RTC\n");
    return -1;
    }
    puts("System time loaded from RTC (UTC).");
    fflush(stdout);
    return 0;
    }

    int main(int argc, char *argv[])
    {
    if (argc > 2) {
    fprintf(stderr, "Usage: RTC [read|write|sync]\n");
    return EXIT_FAILURE;
    }
    const char *mode = argc == 2 ? argv[1] : "read";
    if (strcmp(mode, "read") == 0) {
    } else if (strcmp(mode, "write") == 0) {
    if (set_rtc_from_system() < 0)
    return EXIT_FAILURE;
    } else if (strcmp(mode, "sync") == 0) {
    if (sync_system_from_rtc() < 0)
    return EXIT_FAILURE;
    } else {
    fprintf(stderr, "Usage: RTC [read|write|sync]\n");
    return EXIT_FAILURE;
    }
    return get_rtc_time() < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
    }
  2. Read the RTC time:

    FILE *pipe = popen(HWCLOCK "-r", "r");

    Use popen() to retrieve the time output from hwclock. Check the results of fgets() and pclose(), and display the time only if the read succeeds and the command exits successfully.

  3. Write the system time to the RTC:

    system(HWCLOCK "-w")

    Write the system time to the RTC and use command_succeeded() to check whether the command succeeded. Return a nonzero exit code on failure.

  4. Restore the system time from the RTC:

    system(HWCLOCK "-s")
  5. Main program:

    const char *mode = argc == 2 ? argv[1] : "read";

    The default operation is read-only. When write or sync is selected, perform the corresponding operation, then call get_rtc_time() to display the RTC time.

  6. Cross-compile using the Lume ARM toolchain.

    export PATH=<Luckfox_Lume_SDK>/out/toolchain/gcc-linaro-11.3.1-2022.06-x86_64_arm-linux-gnueabihf/bin:$PATH
    arm-linux-gnueabihf-gcc -std=c11 -O2 -Wall -Wextra RTC.c -o RTC
  7. Run the program:


    chmod +x RTC
    ./RTC read # Read the RTC time
    ./RTC write # Write to the RTC after verifying the system time
    ./RTC sync # Restore the system time from a valid RTC time

    Output:

5. System Clock Synchronization

Network time synchronization first corrects the Linux system time, then writes the accurate time to the RTC. The Lume Buildroot SDK includes BusyBox hwclock and ntpd from the NTP package. The service is managed through /etc/init.d/S49ntp.

  1. Check the time synchronization tools and service:

    command -v hwclock
    command -v ntpd
    ls -l /etc/init.d/S49ntp
    ps | grep -E 'ntpd|phc2sys|ptp4l'
  2. Change the time zone:

    ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    unset TZ
    root@luckfox:~# date -R
    Thu, 03 Sep 2026 21:12:51 +0800

    unset TZ removes the environment variable override in the current shell.

  3. Synchronize the time over the network and write it to the RTC:

    1. Stop the background NTP service first:

      /etc/init.d/S49ntp stop
    2. Run a one-time synchronization in the foreground, then write the system time to the RTC if it succeeds:

      ntpd -g -q -n && hwclock -f /dev/rtc0 -u -w
      • -g: Allow a large time offset to be corrected during the first synchronization.
      • -q: Exit after one synchronization.
      • -n: Run in the foreground so the output is visible.
      • &&: Write to the RTC only if the synchronization command exits successfully.
    3. Check the time after completion:

      date
      hwclock -f /dev/rtc0 -u -r
    4. Finally, restart the background NTP service:

      /etc/init.d/S49ntp start

      The default SDK already starts the service at boot through the S49ntp startup script. No additional systemd commands are needed to enable automatic startup.